package DramScript
{
	import DramCore.Actor;
	
	import GibUI.Sound.SoundControlAS;
	
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	import flash.utils.getTimer;
	
	import mx.containers.Canvas;
	import mx.core.Application;
	
	import utils.Trace;

	public class ScriptLauncher extends Canvas implements IScriptLauncher
	{

		protected var _isPaused:Boolean; // Send ticks to no one
		protected var _scriptStack:Array;
		protected var _sendScriptTicks:Boolean; // When no script - don't tick
		protected var _waitTimerOn:Boolean;
		protected var _waitTimer:Timer;
		protected var _stopWaitTimer:Boolean;
		private var _tickTimer:Timer;
		protected var _startScript:String;
		public   var TICKSPERSECOND:Number = 24;
	 	public static const TICKINTERVAL:Number = 1000 / 24;
		protected static const MAXSCRIPTCOUNT:int = 40; // Maximum number of scripts on stack. Used to detect runaway CALLSCRIPT loops
		private var _lastHotspotClicked:String; // Name of last hotspot clicked
		private var _soundControl:SoundControlAS;
		protected var _actors:Object;

		public function ScriptLauncher():void{
				this._scriptStack = new Array();
				this._sendScriptTicks = false;
				this.isPaused = false;
				this._actors = new Object(); // Associative array
				this._waitTimerOn = false;
				this._stopWaitTimer = false;			
				this._soundControl = Application.application.soundControl;	
		}
	// tickTock() ---- sends ticks to all scripts and things
		public function tickTock(event:TimerEvent):void { 
			if( !this.isPaused ){
				for each(var actor:Object in this._actors ) {
		 			Actor( actor.tickTock(event) );
				}
				if(this._sendScriptTicks && (this._scriptStack.length ) ) {
					// Just send ticks to the top script on the stack
					this._scriptStack[this._scriptStack.length - 1].tickTock(event); 
				}
			} 
		}
		// Sends ticks in a loop as long as there is a script on the stack
		public function runScript( forceStart:Boolean = false ):void{
			this._sendScriptTicks = forceStart;
			this.resetTimer();
		}
		// Game commands from DramScripts come through this function
		public function executeCommand(target:String, command:String, paramArr:Array):ExecuteCommandResult {
			Trace.execCommTrace("ScriptLauncher",target,command,paramArr);
			var ecr:ExecuteCommandResult = new ExecuteCommandResult();
		
		 // trace("GameInterpreter.executeCommand: target: " + target + " command: " + command + " paramArr: " + paramArr);
				switch(target.toLowerCase()){	
					case "game":
						ecr = gameCommands( command, paramArr);
					break; // case "game"
					case "sound":
						if( this.soundControl == null){
							this.soundControl = Application.application.soundControl;
							if( this.soundControl == null){
							Trace.throwError("No soundControl");
							}
						}
						ecr = this.soundControl.executeCommand( target, command, paramArr );
					break;
					case "ui":
					break;
					case "uzer":
					break;
					default:
						Trace.throwError("ScriptLauncher.executeCommand doesn't handle target: "+target);
					break;
				}
				if(ecr.resString == "FAIL") {
					Trace.throwError("ScriptLauncher.executeCommand Problem executing target: " + target + " command: ") + command + " params: " + paramArr;
				} 
			return ecr;
		}
		private function gameCommands( command:String, paramArr:Array):ExecuteCommandResult {
			var ecr:ExecuteCommandResult = new ExecuteCommandResult( );
					switch(command.toUpperCase() ) {
							case "RUNSCRIPT":
								this.popScript();
								this.loadDramScript(paramArr[0]);
							break; 
							case "CALLSCRIPT":   
								this.loadDramScript(paramArr[0]);
							break;
							case "ENDSCRIPT": // Ends most recent script
								if( paramArr[0] == true) { //
//									this.exitThings();
								}
								this.popScript();
							break; 
							case "WAITTIME":
								if(!this._waitTimerOn) {
									this._waitTimer = new Timer( paramArr[0], 1);
		            				this._waitTimer.addEventListener("timer", stopWaitTimer,false,0,true);
									this._waitTimerOn = true;
									this._waitTimer.start();
									ecr = new ExecuteCommandResult("WAIT");
								} else {
									if(this._stopWaitTimer) { // So we return_st "success" to break out of "wait"
										this._stopWaitTimer = false;
									}else {
										ecr = new ExecuteCommandResult("WAIT");
									}
								}
							break;
							case "IFHOTSPOT":
								var branch:Number = 0;
			// trace("ifhotspot lasths: "+lastHotspotClicked+" p[0]: "+ paramArr[0].toLowerCase());
								if( this.lastHotspotClicked != paramArr[0].toLowerCase() ) {
			//trace("branch 1");
									branch = 1;
								} else {
	//			trace("IFHOTSPOT TRUE: " + paramArr[0].toLowerCase());
								}
								// Clear hotspot
								this.lastHotspotClicked = "";
								ecr = new ExecuteCommandResult("BRANCH",branch);
							break;  
							default:
								Trace.throwError("Game.executeCommand doesn't handle command: "+command);
							break; 
					} // switch(command) 

			return ecr;
		}
		// Called from UI. Calls Script to tell it which button was pushed
		// Loads a script and places it on the stack
		public function loadDramScript(script_st:String):void {
			this._sendScriptTicks = false;
			script_st = Application.application._assetPath + "/scripts/"+script_st;
			if( this._scriptStack.length > MAXSCRIPTCOUNT) { // Probably a script-loading loop
				Trace.throwError("Too many scripts loaded. Probably a loop with CALLSCRIPT command.");
			} else {
				this._scriptStack.push( new ScriptExecuter( this,"fullpath",script_st, ScriptDefinition   ) );
			}
		}
		public function scriptLoadedNotification():void {
			Trace.myTrace("GibGame.scriptLoadedNotification");
			this.runScript( true );
		}
		public function setTickInterval( interval:Number = TICKINTERVAL ):void{
			if( this._tickTimer == null) {
				this._tickTimer = new Timer(TICKINTERVAL, 0);
				this._tickTimer.addEventListener("timer", tickTock,false,0,true);
			}
			this._tickTimer.delay = interval;
			this._tickTimer.start();			
		}
		// popScript called by DramScript when it has ended
		public function popScript():void {
			trace("popScript() len before: "+this._scriptStack.length );
			if(this._scriptStack.length > 0) { // There are scripts on the stack
				this._scriptStack.pop() ;
			} else { 
				this._sendScriptTicks = false;
			}
		}
		public function resetTimer():void {
			this._sendScriptTicks = true;
			this.setTickInterval( TICKINTERVAL );
		}
		// shuts off timer for WaitTime command -----------------------------------------
		protected function stopWaitTimer(te:TimerEvent):void {
			Trace.myTrace("stopWaitTimer");
			if(this._waitTimerOn) {
				this._waitTimer = null;
				this._waitTimerOn = false;
				this._stopWaitTimer = true;
			} else {

			}
		}
		public function get isPaused():Boolean {
			return this._isPaused;
		}
		public function set isPaused( b:Boolean ):void {
			this._isPaused = b;
		}
		public function get soundControl():SoundControlAS {
			return this._soundControl;
		}
		public function set soundControl(sc:SoundControlAS):void {
			this._soundControl = sc;
		}
		public function get lastHotspotClicked():String {
	//trace("lastHotspotClicked");
			return this._lastHotspotClicked.toLowerCase();
		}
		
		public function set lastHotspotClicked(hsName:String):void {
			this._lastHotspotClicked = hsName.toLowerCase();
		}
	}
}